<template>
  <div class="wrapper">
    <div
      ref="inputRef"
      class="custom_rich_input"
      :class="{ needsclick: !input }"
      placeholder="请描述您想咨询的问题，留下手机号商家联系您的机率更高"
      :contenteditable="!disable"
      @input="emitChange"
    ></div>
    <div class="flex justify-end" style="padding: 4px 10px">
      <!-- <van-button icon="guide-o" type="primary" color="#00B968" size="small" @click="emit('switchTextMessage')"
        style="padding: 0 20px">
        发送
      </van-button> -->
      <van-button
        type="primary"
        color="#00B968"
        size="small"
        @click="emit('switchTextMessage')"
        style="padding: 0 20px"
      >
        发送
      </van-button>
    </div>
  </div>
</template>

<script setup lang="ts">
import { onBeforeUnmount } from 'vue'

interface CustomEditProps {
  placeholder?: string
  disable?: boolean
  input: string
}

const props = withDefaults(defineProps<CustomEditProps>(), {
  disable: false,
})

const { input, disable } = toRefs(props)
const emit = defineEmits(['update:input', 'change', 'triggerAt', 'switchTextMessage'])

const inputRef = ref<HTMLDivElement>()
let latestHtml = ''
let cursorPos: Range

onUpdated(() => {
  latestHtml = input.value
})

const regex = new RegExp('<img', 'i')
const emitChange = () => {
  const content = inputRef.value?.innerHTML
  if (!content) {
    return
  }

  if (regex.test(content as string)) {
    inputRef.value!.innerHTML = latestHtml
    const length = latestHtml.length
    // 设置光标位置到末尾
    const selection = window.getSelection()
    if (selection) {
      const range = document.createRange()
      const textNode = document.createTextNode('')
      inputRef.value!.appendChild(textNode)
      range.setStart(textNode, 0)
      range.collapse(true)
      selection.removeAllRanges()
      selection.addRange(range)
      textNode.remove() // 移除临时文本节点
    }
    // 聚焦元素
    inputRef.value!.focus()
    return
  }

  emit('change', content)
  if (content !== latestHtml) {
    emit('update:input', content)
  }
  latestHtml = content!
}

const clear = () => {
  inputRef.value!.innerHTML = ''
}

const insertAtCursor = (nodes: Node[]) => {
  if (!cursorPos) return
  const selection = window.getSelection()
  const range = cursorPos.cloneRange()

  range.deleteContents()
  nodes.forEach((node) => {
    range.insertNode(node)
    range.setStartAfter(node)
  })
  range.collapse(false)
  selection!.removeAllRanges()
  selection!.addRange(range)
  emitChange()
}

const deletePreviousChar = () => {
  if (!cursorPos) return
  const range = cursorPos.cloneRange()
  const previousChar = range.startContainer.textContent!.charAt(range.startOffset - 1)
  if (previousChar === '@') {
    range.setStart(range.startContainer, range.startOffset - 1)
    range.deleteContents()
  }
}

const updateCursorPosition = () => {
  const selection = window.getSelection()
  if (selection && selection.rangeCount > 0) {
    cursorPos = selection.getRangeAt(0)
  }
}

const onSelectionChange = () => {
  if (inputRef.value === document.activeElement) {
    updateCursorPosition()
  }
}

onMounted(() => {
  document.addEventListener('selectionchange', onSelectionChange)
})

onBeforeUnmount(() => {
  document.removeEventListener('selectionchange', onSelectionChange)
})

defineExpose({
  inputRef,
  insertAtCursor,
  deletePreviousChar,
  clear,
})
</script>

<style lang="scss" scoped>
.wrapper {
  width: 100%;
  border-radius: 8px;
}

.custom_rich_input {
  position: relative;
  height: 60px;
  padding: 0 10px;
  color: rgba(0, 0, 0, 0.85);
  font-size: 14px;
  transition: all 0.3s;
  outline: none;
  white-space: pre-wrap;
  word-break: break-all;
  overflow: auto;
  -webkit-overflow-scrolling: touch;
  cursor: text;
  min-height: 32px;
  max-height: 100px;
  user-select: auto;
  // fix safari input
  -webkit-user-select: auto;

  :deep(.face_el) {
    display: inline-block;
    vertical-align: text-bottom;
  }

  &::-webkit-scrollbar {
    display: none;
  }
}

.needsclick {
  &::before {
    position: absolute;
    content: attr(placeholder);
    color: rgb(169, 169, 169);
  }
}
</style>
